package com.foton.lotterydomain.strategy.service.draw;

import com.foton.lotterycommon.common.Constants;
import com.foton.lotterydomain.strategy.model.aggregates.StrategyRich;
import com.foton.lotterydomain.strategy.model.req.DrawReq;
import com.foton.lotterydomain.strategy.model.res.DrawResult;
import com.foton.lotterydomain.strategy.model.vo.*;
import com.foton.lotterydomain.strategy.service.algorithm.IDrawAlgorithm;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author RenPu
 * @Date 2023/11/24 15:07
 * @Version 1.0
 * @Description: 抽奖公共基础类设计：业务流程的编排，公共方法的实现【检查是否进行数据的初始化操作，】
 **/
@Slf4j
public abstract class AbstractDrawBase extends DrawStrategySupport implements IDrawExec {

    @Override
    public DrawResult doIDrawExec(DrawReq req) {

        //1:根据用户ID，策略ID查询对应的策略以及策略明细
        StrategyRich strategyRich = super.queryStrategyRich(req.getStrategyId());
        StrategyBriefVO strategy = strategyRich.getStrategy();

        // 校验和初始化数据到内存中
        this.checkAndInitRateData(req.getStrategyId(), strategy.getStrategyMode(), strategyRich.getStrategyDetailList());

        //   获取不在抽奖范围内的列表，包括：奖品库存为空、风控策略、临时调整等，这类数据是含有业务逻辑的，
        //   所以需要由具体的实现方决定
        List<String> excludeList = this.queryExcludeAwardIds(req.getStrategyId());
        IDrawAlgorithm iDrawAlgorithm = drawAlgorithmstateMap.get(strategy.getStrategyMode());

        // 根据抽奖算法获取商品的ID值
        String awardId = drawAlgorithm(strategy.getStrategyId(), iDrawAlgorithm, excludeList);

        return buildDrawResult(req.getUId(), strategy.getStrategyId(), awardId,strategy);

    }


    /**
     * 获取不在抽奖范围内的列表，包括：奖品库存为空、风控策略、临时调整等，这类数据是含有业务逻辑的，
     * 所以需要由具体的实现方决定
     *
     * @param strategyId 策略ID
     * @return 排除的奖品ID集合
     */
    protected abstract List<String> queryExcludeAwardIds(Long strategyId);


    /**
     * 根据抽奖算法的计算，获取对应的商品ID值
     *
     * @param strategyId
     * @param drawAlgorithm
     * @param excludeAwardIds
     * @return
     */
    protected abstract String drawAlgorithm(Long strategyId, IDrawAlgorithm drawAlgorithm, List<String> excludeAwardIds);


    /**
     * 检查数据是否进行初始化，否的话则进行数据初始化
     *
     * @param strategyId
     * @param strategyMode
     * @param strategyDetailList
     */
    protected void checkAndInitRateData(Long strategyId, Integer strategyMode, List<StrategyDetailBriefVO> strategyDetailList) {

        // 非单项概率【商家为了谋取利益的手段】，不必存入缓存
        if (!Constants.StrategyMode.SINGLE.getCode().equals(strategyMode)) {
            return;
        }
        IDrawAlgorithm drawAlgorithm = this.drawAlgorithmstateMap.get(strategyMode);

        // 已初始化过的数据，不必重复初始化
        if (drawAlgorithm.isExistRateTuple(strategyId)) {
            return;
        }
        // 解析并初始化中奖概率数据到散列表
        List<AwardRateInfo> awardRateInfoList = new ArrayList<>(strategyDetailList.size());
        for (StrategyDetailBriefVO strategyDetail : strategyDetailList) {
            awardRateInfoList.add(new AwardRateInfo(strategyDetail.getAwardId(), strategyDetail.getAwardRate()));
        }
        drawAlgorithm.initRateTuple(strategyId, awardRateInfoList);

    }


    /**
     * 包装抽奖数据结果
     *
     * @param uId
     * @param strategyId
     * @param awardId
     * @return
     */
    public DrawResult buildDrawResult(String uId, Long strategyId, String awardId,StrategyBriefVO strategy) {
        if (null == awardId) {
            log.info("执行策略抽奖完成【未中奖】，用户：{} 策略ID：{}", uId, strategyId);
            return new DrawResult(uId, strategyId, 400);
        }

        AwardBriefVO award = this.queryAwardInfo(awardId);
        DrawAwardInfo drawAwardInfo = new DrawAwardInfo(uId,award.getAwardId(), award.getAwardType(), award.getAwardName(), award.getAwardContent(),strategy.getStrategyMode(),strategy.getGrantType(),strategy.getGrantDate());
        log.info("执行策略抽奖完成【已中奖】，用户：{} 策略ID：{} 奖品ID：{} 奖品名称：{}", uId, strategyId, awardId, award.getAwardName());

        return new DrawResult(uId, strategyId, Constants.DrawState.SUCCESS.getCode(), drawAwardInfo);
    }
}
